﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
//using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Windows.Forms;
using TRicheControl.Comm;

namespace TRicheControl.WinformControl
{
    [ToolboxBitmap(typeof(TreeView))]
    public partial class RicheTreeView : Control
    {
        private List<RicheTreeNode> mDisplayNodes = new List<RicheTreeNode>();
        
        private RicheTreeNode mFousedNode = null;
        
        private RicheVScrollBar mScrollBar;
        
        private RicheTreeNodeCollection mNodes;
        
        private int mNodeHeight = 30;
        
        private int mNodeInterval = 1;
        
        private Graphics mGraphics;
        
        private int mTreeViewHeight = 0;
        
        private int mTop = 0;
        
        public RicheTreeNodeCollection Nodes
        {
            get
            {
                return mNodes;
            }
        }

        public int NodeHeight
        {
            get
            {
                return mNodeHeight;
            }
            set
            {
                mNodeHeight = value;
            }
        }

        public int NodeInterval
        {
            get
            {
                return mNodeInterval;
            }
            set
            {
                mNodeInterval = value;
            }
        }
        
        public Graphics Graphics
        {
            get
            {
                if (base.IsDisposed)
                {
                    return null;
                }
                if (mGraphics == null)
                {
                    mGraphics = base.CreateGraphics();
                }
                return mGraphics;
            }
        }

        public RicheTreeView()
        {
            InitializeComponent();

            this.SetStyle(ControlStyles.OptimizedDoubleBuffer |
                          ControlStyles.ResizeRedraw |
                          ControlStyles.AllPaintingInWmPaint, true);

            mNodes = new RicheTreeNodeCollection(null);
            mNodes.OnItemChnageEvent += mNodes_OnItemChnageEvent;

            mScrollBar = new RicheVScrollBar();
            mScrollBar.Visible = false;
            mScrollBar.AllDisplayHeight = 0;
            mScrollBar.CurrentDisplayHeight = 0;
            mScrollBar.Dock = System.Windows.Forms.DockStyle.Right;
            mScrollBar.Name = "ScorllBar";
            mScrollBar.ScrollLenght = 5;
            mScrollBar.SilderHeight = 20;
            mScrollBar.Size = new System.Drawing.Size(22, 581);
            mScrollBar.TabIndex = 1;
            mScrollBar.Value = 0;
            mScrollBar.OnScroll += mScrollBar_OnScroll;
            this.Controls.Add(mScrollBar);
        }

        private void mScrollBar_OnScroll(object sender, EventArgs e)
        {
            mTop = mScrollBar.Value;
            ResetNodeRects();
            this.Refresh();
        }

        private void mNodes_OnItemChnageEvent(Comm.ItemChangeType changeType, RicheTreeNode node)
        {
            if (changeType == Comm.ItemChangeType.Add)
            {
                node.OnParentNodeChange += node_OnParentNodeChange;
                node.ChildNodes.OnItemChnageEvent += mNodes_OnItemChnageEvent;
            }
            else if (changeType == Comm.ItemChangeType.Remove)
            {
                node.OnParentNodeChange -= node_OnParentNodeChange;
                node.ChildNodes.OnItemChnageEvent -= mNodes_OnItemChnageEvent;
            }
            ResetNodeRects();
        }

        private void node_OnParentNodeChange(RicheTreeNode node)
        {
            ResetNodeRects();
            this.Refresh();
        }

        private void ResetNodeRects()
        {
            mDisplayNodes.Clear();
            mTreeViewHeight = 0;
            for (int index = 0; index < Nodes.Count; index++)
            {
                RicheTreeNode beforeNode = null;
                RicheTreeNode node = Nodes[index];
                if(index > 0)
                {
                    beforeNode = Nodes[index - 1];
                }
                ResetNodeRects(beforeNode, node);
                mTreeViewHeight += node.Rectangle.Height;
            }
            if (mTreeViewHeight > this.Height)
            {
                mScrollBar.Visible = true;
                mScrollBar.AllDisplayHeight = mTreeViewHeight;
                mScrollBar.CurrentDisplayHeight = this.Height;
            }
            else
            {
                mScrollBar.Visible = false;
            }
        }

        private void ResetNodeRects(RicheTreeNode beforeNode ,RicheTreeNode node)
        {
            int nodeWidth = this.Width;
            Rectangle rect = new Rectangle();
            if (beforeNode != null)
            {
                rect.X = 0;
                rect.Y = beforeNode.Bounds.Y + beforeNode.Rectangle.Height + mNodeInterval;
                rect.Width = nodeWidth;
                rect.Height = mNodeHeight;
            }
            else if (node.ParentNode != null)
            {
                rect.X = 0;
                rect.Y = node.ParentNode.Bounds.Y + node.ParentNode.Bounds.Height + mNodeInterval;
                rect.Width = nodeWidth;
                rect.Height = mNodeHeight;
            }
            else
            {
                rect.X = 0;
                rect.Y = mNodeInterval - mTop;
                rect.Width = nodeWidth;
                rect.Height = mNodeHeight;
            }
            node.Bounds = rect;
            if (node.Bounds.X >= 0 && node.Bounds.X <= this.Width && node.Bounds.Y >= 0 && node.Bounds.Y <= this.Height
             || node.Bounds.X + node.Bounds.Height >= 0 && node.Bounds.X + node.Bounds.Height <= this.Width)
            {
                mDisplayNodes.Add(node);
            }
            if (!node.IsExpand)
            {
                node.Rectangle = Rectangle.Empty;
                return;
            }
            int rectHeight = 0;
            for (int index = 0; index < node.ChildNodes.Count; index++ )
            {
                RicheTreeNode inBeforeNode = null;
                RicheTreeNode inNode = node.ChildNodes[index];
                if (index > 0)
                {
                    inBeforeNode = node.ChildNodes[index - 1];
                }
                ResetNodeRects(inBeforeNode, inNode);
                rectHeight += inNode.Rectangle.Height + mNodeInterval;
            }
            if (node.ChildNodes.Count < 1)
                return;
            RicheTreeNode lastNode = node.ChildNodes[node.ChildNodes.Count - 1];
            node.Rectangle = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + rectHeight);
        }

        private Rectangle GetExpanMarkBounds(RicheTreeNode node)
        {
            return Rectangle.Empty;
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            DrawTreeNodes(pe.Graphics);
            DrawTreeView(pe.Graphics);
        }

        private void DrawTreeView(Graphics g)
        {
            Rectangle drawRect = new Rectangle(0, 0, this.Width, this.Height);
            if (this.Enabled)
            {
                GraphicsStyle.Styles.TreeViewStyle.DrawEnbaleTreeView(g, drawRect);
            }
            else
            {
                GraphicsStyle.Styles.TreeViewStyle.DrawUnEnbaleTreeView(g, drawRect);
            }
        }

        private void DrawTreeNodes(Graphics g)
        {
            foreach (RicheTreeNode node in mDisplayNodes)
            {
                if (node.ChildNodes.Count > 0)
                {
                    if (node.IsExpand)
                    {
                        GraphicsStyle.Styles.TreeViewStyle.DrawExpandNode(node, g);
                    }
                    else
                    {
                        GraphicsStyle.Styles.TreeViewStyle.DrawUnExpandNode(node, g);
                    }
                }
                else
                {
                    GraphicsStyle.Styles.TreeViewStyle.DrawTreeNode(node, g);
                }
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if(mFousedNode != null)
            {
                if (ControlHelper.PointInArea(e.Location, mFousedNode.Bounds))
                    return;
            }
            foreach (RicheTreeNode node in mDisplayNodes)
            {
                if (!ControlHelper.PointInArea(e.Location, node.Bounds))
                    continue;
                if (mFousedNode != null)
                {
                    mFousedNode.IsFocused = false;
                }
                mFousedNode = node;
                mFousedNode.IsFocused = true;
                break;
            }
            this.Refresh();
            base.OnMouseMove(e);
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            if (mFousedNode != null && ControlHelper.PointInArea(e.Location, mFousedNode.Bounds))
            {
                mFousedNode.IsExpand = !mFousedNode.IsExpand;
                ResetNodeRects();
                this.Refresh();
            }
            base.OnMouseClick(e);
        }
    }
}
